package dao

import (
	"context"
	"errors"
	"fmt"

	"bilinadmin/pkg/util"

	"bilinadmin/internal/object"

	"bilinadmin/pkg/db/pgex"

	"bilinadmin/internal/model"
)

// OperatorDao operator dao
type OperatorDao interface {
	// CreateOperator 创建运营
	CreateOperator(ctx context.Context, op *model.Operator) (int64, error)
	// CreateOperators 创建运营
	CreateOperators(ctx context.Context, ops []*model.Operator) error
	// UpdateOperatorById  更新角色
	UpdateOperatorById(ctx context.Context, op *model.Operator) error
	// UpdateOperatorByIds 更新角色
	UpdateOperatorByIds(ctx context.Context, ops []*model.Operator) error
	// GetOperator 获取运营角色
	GetOperator(ctx context.Context, empId, refId int64, retType int8) (*model.Operator, error)
	// LockOperator 锁定角色
	LockOperator(ctx context.Context, empId, refId int64, retType int8) (*model.Operator, error)
	// GetOperators 加载运营列表
	GetOperators(ctx context.Context, brandId, refId int64, refType, status int8, search string, pagination *object.Pagination) ([]*object.OpSimpleInfo, uint32, error)
	// DelOperatorById 删除运营
	DelOperatorById(ctx context.Context, op *model.Operator) error
	// DelOperatorByIds 删除运营 by ids
	DelOperatorByIds(ctx context.Context, ops []*model.Operator, modifier int64) error
	// LockOperatorsByRefIds 根据ref_ids 锁定某个员工运营列表
	LockOperatorsByRefIds(ctx context.Context, brandId, empId int64, refType int8, refIds []int64) ([]*model.Operator, error)
	// GetOperatorsByRefIds 根据ref_ids 加载某个员工运营列表
	GetOperatorsByRefIds(ctx context.Context, brandId, empId int64, refType int8, refIds []int64) ([]*model.Operator, error)
	// GetValidOperatorByEmpId 获取有效运营角色
	GetValidOperatorByEmpId(ctx context.Context, brandId, empId int64) ([]*model.Operator, error)
}

var opDao OperatorDao

type opImpl struct {
	*DaoBase
	name string
}

// InitOperatorDao 初始化 dao
func InitOperatorDao() {
	opDao = &opImpl{
		DaoBase: daoBase,
		name:    "operator_dao",
	}
}

// GetOperatorDao 获取 dao
func GetOperatorDao() OperatorDao {
	return opDao
}

// CreateOperator 创建运营
func (dao *opImpl) CreateOperator(ctx context.Context, op *model.Operator) (int64, error) {
	if op == nil {
		return 0, nil
	}
	param := []interface{}{
		op.BrandId,
		op.RefId,
		op.RefType,
		op.EmpId,
		op.RoleId,
		op.Status,
		op.CustomPerSet,
		op.ModifyEmpId,
		op.CreatedAt,
		op.UpdatedAt,
	}
	query := "INSERT INTO operator (brand_id, ref_id, ref_type, emp_id, role_id, status, custom_per_set, modify_emp_id, " +
		"created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"
	aff, err := dao.db.PgExec(ctx, "id", query, param...)
	if err != nil {
		return 0, err
	}
	lastId, _ := aff.GetLastId()
	return lastId, nil
}

// CreateOperators 创建运营
func (dao *opImpl) CreateOperators(ctx context.Context, ops []*model.Operator) error {
	if len(ops) == 0 {
		return nil
	}
	params := make([][]interface{}, len(ops))
	for idx, op := range ops {
		params[idx] = []interface{}{
			op.BrandId,
			op.RefId,
			op.RefType,
			op.EmpId,
			op.RoleId,
			op.Status,
			op.CustomPerSet,
			op.ModifyEmpId,
			op.CreatedAt,
			op.UpdatedAt,
		}
	}
	query := "INSERT INTO operator (brand_id, ref_id, ref_type, emp_id, role_id, status, custom_per_set, modify_emp_id, " +
		"created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"
	_, err := dao.db.InsertMany(ctx, query, params)
	return err
}

// UpdateOperatorById 更新角色
func (dao *opImpl) UpdateOperatorById(ctx context.Context, op *model.Operator) error {
	if op == nil {
		return nil
	}
	param := []interface{}{
		op.RoleId,
		op.CustomPerSet,
		op.ModifyEmpId,
		op.Status,
		op.UpdatedAt,
		op.Id,
	}
	query := "UPDATE operator SET role_id=?, custom_per_set=?, modify_emp_id=?, status=?, updated_at=? WHERE id=? AND deleted_at=0"
	_, err := dao.db.Update(ctx, query, param...)
	return err
}

// UpdateOperatorByIds 更新运营角色
func (dao *opImpl) UpdateOperatorByIds(ctx context.Context, ops []*model.Operator) error {
	if len(ops) == 0 {
		return nil
	}
	params := make([][]interface{}, len(ops))
	for idx, op := range ops {
		params[idx] = []interface{}{
			op.RoleId,
			op.CustomPerSet,
			op.ModifyEmpId,
			op.Status,
			op.UpdatedAt,
			op.Id,
		}
	}
	query := "UPDATE operator SET role_id=?, custom_per_set=?, modify_emp_id=?, status=?, updated_at=? WHERE id=? AND deleted_at=0"
	_, err := dao.db.UpdateMany(ctx, query, params)
	return err
}

// GetOperator 获取运营角色
func (dao *opImpl) GetOperator(ctx context.Context, empId, refId int64, retType int8) (*model.Operator, error) {
	query := "SELECT * FROM operator WHERE emp_id=? AND ref_id=? And ref_type=? AND deleted_at=0"
	op := &model.Operator{}
	err := dao.db.Get(ctx, op, query, empId, refId, retType)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return op, err
}

// LockOperator 锁定角色
func (dao *opImpl) LockOperator(ctx context.Context, empId, refId int64, retType int8) (*model.Operator, error) {
	if err := dao.needTrans(ctx); err != nil {
		return nil, err
	}
	query := "SELECT * FROM operator WHERE emp_id=? AND ref_id=? And ref_type=? AND deleted_at=0 FOR UPDATE"
	op := &model.Operator{}
	err := dao.db.Get(ctx, op, query, empId, refId, retType)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return op, err
}

// GetOperators 加载运营列表
func (dao *opImpl) GetOperators(ctx context.Context, brandId, refId int64, refType, status int8, search string, pg *object.Pagination) ([]*object.OpSimpleInfo, uint32, error) {
	where := "FROM operator AS dao INNER JOIN employee AS e ON dao.emp_id=e.id WHERE dao.deleted_at=0 AND e.deleted_at=0 "
	where += fmt.Sprintf("AND dao.brand_id=%d AND dao.ref_id=%d AND dao.ref_type=%d ", brandId, refId, refType)
	if status != 0 {
		where += fmt.Sprintf(" AND dao.status=%d", status)
	}
	if search != "" {
		where += fmt.Sprintf(" AND (e.name='%s' OR e.mobile='%s')", search, search)
	}
	// 计算数量
	total, err := dao.CountNum(ctx, where)
	if err != nil {
		return nil, 0, err
	}

	var ops []*object.OpSimpleInfo
	query := fmt.Sprintf("SELECT e.id AS emp_id, e.name, e.mobile, dao.role_id, dao.status, dao.id AS op_id %s %s", where, pg.GetDbOffset())
	err = dao.db.Query(ctx, &ops, query)
	return ops, total, err
}

// DelOperatorById 删除运营
func (dao *opImpl) DelOperatorById(ctx context.Context, op *model.Operator) error {
	if op == nil {
		return nil
	}
	if op.DeletedAt == 0 {
		op.DeletedAt = util.GetCurrentTimestamp()
	}
	query := "UPDATE operator SET modify_emp_id=?, deleted_at=? WHERE id=? AND deleted_at=0"
	_, err := dao.db.Update(ctx, query, op.ModifyEmpId, op.DeletedAt, op.Id)
	return err
}

// DelOperatorByIds 删除运营 by ids
func (dao *opImpl) DelOperatorByIds(ctx context.Context, ops []*model.Operator, modifier int64) error {
	if len(ops) == 0 {
		return nil
	}
	ids := make([]int64, len(ops))
	for idx, op := range ops {
		ids[idx] = op.Id
	}
	now := util.GetCurrentTimestamp()
	query := "UPDATE operator SET modify_emp_id=?, deleted_at=? WHERE id IN ? AND deleted_at=0"
	_, err := dao.db.Update(ctx, query, modifier, now, ids)
	return err
}

// LockOperatorsByRefIds 加载仓库运营列表
func (dao *opImpl) LockOperatorsByRefIds(ctx context.Context, brandId, empId int64, refType int8, refIds []int64) ([]*model.Operator, error) {
	if len(refIds) == 0 {
		return nil, nil
	}
	err := dao.needTrans(ctx)
	if err != nil {
		return nil, err
	}
	var ops []*model.Operator
	query := "SELECT id, brand_id, ref_id, ref_type, role_id, custom_per_set, status FROM operator WHERE brand_id=? AND emp_id=? " +
		"AND ref_type=? AND ref_id IN ? AND deleted_at=0 FOR UPDATE"
	err = dao.db.Query(ctx, &ops, query, brandId, empId, refType, refIds)
	return ops, err
}

// GetOperatorsByRefIds 根据ref_ids 加载某个员工运营列表
func (dao *opImpl) GetOperatorsByRefIds(ctx context.Context, brandId, empId int64, refType int8, refIds []int64) ([]*model.Operator, error) {
	if len(refIds) == 0 {
		return nil, nil
	}
	var ops []*model.Operator
	query := "SELECT id, brand_id, ref_id, ref_type, role_id, custom_per_set, status FROM operator WHERE brand_id=? AND emp_id=? " +
		"AND ref_type=? AND ref_id IN ? AND deleted_at=0"
	err := dao.db.Query(ctx, &ops, query, brandId, empId, refType, refIds)
	return ops, err
}

// GetValidOperatorByEmpId 获取有效运营角色
func (dao *opImpl) GetValidOperatorByEmpId(ctx context.Context, brandId, empId int64) ([]*model.Operator, error) {
	var ops []*model.Operator
	query := "SELECT id, brand_id, ref_id, ref_type, emp_id, role_id FROM operator WHERE brand_id=? AND emp_id=? AND status=? AND deleted_at=0"
	err := dao.db.Query(ctx, &ops, query, brandId, empId, model.OpStatusValid)
	return ops, err
}
